import 'dart:async';

import 'package:flutter/material.dart';
import './path_plan_options.dart';
import 'package:flutter_map/plugin_api.dart';
import './path_plan_event.dart';
import './path_plan_event_actions.dart';
import 'package:dio/dio.dart';

///@className animate_polyline_layer
///@author liaoyu
///@version 1.0.0
///@description 带动画的polyline
///@createTime 2021/1/8 11:09
class PathPlanLayer extends StatefulWidget {
  final PathPlanOptions options;
  final MapState mapState;
  final Stream<Null> stream;

  const PathPlanLayer({Key key, this.options, this.mapState, this.stream}) : super(key: key);

  @override
  _PathPlanLayerState createState() => _PathPlanLayerState();
}

class _PathPlanLayerState extends State<PathPlanLayer> {
  ValueNotifier<int> _vnPointsIndex;
  Timer _timer;
  List<Polyline> polylines = [];
  int _currentIndex = 0;
  final pathUrl = 'https://restapi.amap.com/v3/direction/driving';

  @override
  void initState() {
    _vnPointsIndex = ValueNotifier(0);
    widget.options.pathPlanController.streamController = StreamController<PathPlanEvent>.broadcast();
    widget.options.pathPlanController.streamController.stream.listen((PathPlanEvent pathPlanEvent) => _handleAction(pathPlanEvent));
    _initPathData();
    super.initState();
  }

  @override
  void dispose() {
    widget.options.pathPlanController.streamController.close();
    _stop();
    _vnPointsIndex.dispose();
    super.dispose();
  }

  void _handleAction(PathPlanEvent event) {
    switch (event.action) {
      case PathPlanActions.start:
        return _start();
      case PathPlanActions.stop:
        return _stop();
      case PathPlanActions.cancel:
        return _cancel();
    }
  }

  void _start() {
    Future.delayed(Duration(milliseconds: 200), () {
      _timer = Timer.periodic(Duration(milliseconds: 100), (timer) => _countDown());
    });
  }

  void _initPathData() async {
    Map<String,String> paras = {
      'origin':'${widget.options.origin.longitude},${widget.options.origin.latitude}',
      'destination':'${widget.options.destination.longitude},${widget.options.destination.latitude}',
      'key':'43c9bc725036b7fce59482931d1ba001'
    };
    Response response = await Dio().request(
      pathUrl,
      queryParameters: paras,
    );
    if (response != null) {
      print(response.data);
    }
  }

  void _countDown() {
    if(polylines.isEmpty)_stop();
    if (_vnPointsIndex.value < (polylines.length-1)) {
      _vnPointsIndex.value = _vnPointsIndex.value+1;
      _currentIndex = _vnPointsIndex.value;
    } else {
      _stop();
    }
  }

  void _cancel() {
    _stop();
    _vnPointsIndex.value = 0;
    _currentIndex = _vnPointsIndex.value;
  }

  void _stop() {
    if (_timer != null) {
      _timer.cancel();
      _timer = null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints bc) {
        final size = Size(bc.maxWidth, bc.maxHeight);
        return _build(context, size);
      },
    );
  }

  Widget _build(BuildContext context, Size size) {
    return StreamBuilder<void>(
      stream: widget.stream, // a Stream<void> or null
      builder: (BuildContext context, _) {
        return ValueListenableBuilder(
            valueListenable: _vnPointsIndex,
            builder: (BuildContext context, int value, Widget child) {
              if (value == 0) return Container();
              List<Polyline> _subPolylines = polylines.sublist(0,value);
              for (var polylineOpt in _subPolylines) {
                polylineOpt.offsets.clear();
                var i = 0;
                for (var point in polylineOpt.points) {
                  var pos = widget.mapState.project(point);
                  pos = pos.multiplyBy(widget.mapState.getZoomScale(widget.mapState.zoom, widget.mapState.zoom)) -
                      widget.mapState.getPixelOrigin();
                  polylineOpt.offsets.add(Offset(pos.x.toDouble(), pos.y.toDouble()));
                  if (i > 0 && i < polylineOpt.points.length) {
                    polylineOpt.offsets
                        .add(Offset(pos.x.toDouble(), pos.y.toDouble()));
                  }
                  i++;
                }
              }
              return Container(
                child: Stack(
                  children: [
                    for (final polylineOpt in _subPolylines)
                      CustomPaint(
                        painter: PolylinePainter(polylineOpt),
                        size: size,
                      ),
                  ],
                ),
              );
            });
      },
    );
  }
}
